#pragma once

#include "DX11Includes.h"
#include "SceneParser.h"
#include <map>
#include <algorithm> 
#include <stdio.h>
#include <assimp.hpp>      // C++ importer interface
#include <aiScene.h>       // Output data structure
#include <aiPostProcess.h> // Post processing flags

#include "MeshUtils.h"
#include "Camera.h"
#include "ILight.h"
#include "DefaultLogger.h"
#include "SceneAnimator.h"

#pragma comment (lib, "assimp.lib")

class IMesh;

#define MODEL_XMLModel 0x0001
#define MODEL_QUAD 0x0002
#define MODEL_BOX 0x0003
#define MODEL_GenericScene 0x0004

#define DIFFUSE_MAP "Diffuse"

enum SceneType
{
	XML,GENERIC
};

struct SceneElements
{
	vector<Camera*> Camera;
	vector<ILight*> Light;
	vector<IMesh*> Mesh;
};

using namespace std;

class MeshFactory
{
public:
	MeshFactory(void);
	~MeshFactory(void);
	IMesh* LoadModel(const char* scenePath ,const char* meshName, MeshTypeData meshType = MeshTypeData::PositionTextureNormal, unsigned char ModelType = MODEL_XMLModel ,bool cacheLoadedModel = true);
	SceneElements* LoadScene(const char* scenePath ,SceneType = SceneType::GENERIC ,bool cacheLoadedScene = true, bool KeepModelDateInRam = false);	
	IMesh* LoadAssimpSingleModel(const char* scenePath ,bool cacheLoadedScene = true, bool KeepModelDateInRam = false);

protected:	
	map<unsigned char,IMesh* (*)(const char* scenePath ,const char* meshName, MeshTypeData meshType,bool cacheLoadedModel )> MeshCreators;			
	map<const char* , IMesh*> cache;	
	SceneAnimNode* CopyNodesWithMeshes(const aiScene*,aiNode* node, SceneElements* elements, aiMatrix4x4 accTransform,SceneAnimNode* pParent,bool KeepModelDateInRam = false);	
	MeshTypeData  GetVertexData(VertexData* outData,UINT** indices, aiMesh* mesh) ;
	vector<std::pair<XMFLOAT4X4,int>> ProcessBones(aiNode* root,aiMesh* mesh,PositionTextureNormalTangentBinormalAnimatedVertex* vertexData);	
private:
	static IMesh* LoadXMLModel(const char* scenePath ,const char* meshName, MeshTypeData meshType , bool cacheLoadedModel);
	static IMesh* LoadQuad(const char* scenePath ,const char* meshName, MeshTypeData meshType , bool cacheLoadedModel);
	static IMesh* LoadBox(const char* scenePath ,const char* meshName, MeshTypeData meshType , bool cacheLoadedModel);
	std::map<aiNode*,SceneAnimNode*> nodeSceneMap;	
	vector<SceneAnimNode*> Nodes;
};

inline XMMATRIX TOXMMATRIX(aiMatrix4x4 transform)
{
			return XMMatrixSet(transform.a1,transform.a2,transform.a3,transform.a4,
			transform.b1,transform.b2,transform.b3,transform.b4,
			transform.c1,transform.c2,transform.c3,transform.c4,
			transform.d1,transform.d2,transform.d3,transform.d4);				
}

inline XMFLOAT4X4 TOXMFLOAT4X4(aiMatrix4x4 transform)
{
	return XMFLOAT4X4(transform.a1,transform.a2,transform.a3,transform.a4,
			transform.b1,transform.b2,transform.b3,transform.b4,
			transform.c1,transform.c2,transform.c3,transform.c4,
			transform.d1,transform.d2,transform.d3,transform.d4);			
}






